/**
 * @class   wosh::Session
 * @brief   
 *
 ****************************************************************************
 * @version $Id: Session.h 2883 2010-08-09 14:51:56Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_Session_H__
 #define __WOSH_Core_Session_H__

 #include <core/Object.h>
 #include <core/Containers.h>
 #include <core/BusConnector.h>
 #include <core/LogContext.h>
 #include <core/SecurityToken.h>
 #include <core/Fact.h>

namespace wosh {

 #define _Session_EVENT_ListChanged			"Session_ListChanged"

#define WOSH_SESSION(CLASSNAME)			\
		WOSH_CLASSNAME(CLASSNAME)		\
		WOSH_CLASS_ABSTRACT(false)


class SessionProtocol;
class SessionManager;
template <class T> class DataFieldCollector;

class Session :	public Object,
				public virtual IBusListener
 {
	WOSH_CLASSNAME(wosh::Session)
	WOSH_CLASS_ABSTRACT(true)

	public:
		/**
		 * @brief   states of a session
		 */
		enum SESSION_STATE {
			STATE_UNKNOWN		= 0x0000,
			STATE_CREATED		= 0x0001,	///< "allocated"
			STATE_LOGGING		= 0x0002,	///< logging
			STATE_LOGGING_USER	= 0x0006,	///< =2+4, logging (entering/parsing username)
			STATE_LOGGING_PWD	= 0x000A,	///< =2+8, logging (entering/parsing password)
			STATE_LOGGING_CHK	= 0x0012,	///< =2+16, logging (validating credentials,user,password)
			STATE_LOGGING_LOGGED= 0x0022,	///< =2+32, logging (just logged)
			STATE_OPENED		= 0x0040,	///< session is active
			STATE_CLOSED		= 0x0080,	///< session is closed, may be deleted
			STATE_FAILURE		= 0x0100	///< session is closed(failed), may be deleted
		 };

		enum SESSION_RESTRICTIONS {
			ALLOW_NOTHING		= 0x00,
			ALLOW_ROOT			= 0x01,
			ALLOW_SU			= 0x02,
			ALLOW_SUDO			= 0x04,
			ALLOW_ALL			= 0xFF
		 };

	public:
		Session();
		//Session( const Session& session );
		virtual ~Session();


	public:
		virtual WRESULT open( unsigned long timeout = LIMIT_ULONG_MAX );
		virtual WRESULT close( unsigned long timeout = LIMIT_ULONG_MAX );

		virtual WRESULT su( const std::string& username );


/** @name Message Events (incoming message)
 * @{
 ******************************************************************************/
	public:
		virtual void busMessage( const Message& message, const Bus* source );
//@}
/** @name Getters
 * @{
 ******************************************************************************/
	public:
		inline long getID() const							{ return this->id; }
		inline long getCreationTS() const					{ return this->creation_ts; }
		inline const URI& getCreatorURI() const				{ return this->creator; }

		inline SESSION_STATE getState() const				{ MutexLockerRead(&this->stateLock); return this->state; }
		inline bool isLogging() const						{ return (getState() == Session::STATE_LOGGING); }
		inline bool isOpened() const						{ return (getState() == Session::STATE_OPENED); }
		inline bool isClosed() const						{ return (getState() == Session::STATE_CLOSED); }
		inline bool isFailed() const						{ return (getState() == Session::STATE_FAILURE); }

		inline const std::string& getUsernameLogged() const	{ return this->usernameLogged; }
		inline const std::string& getUsername() const		{ MutexLockerRead(&this->loggingLock); return this->username; }
// credentials
// protocol 		inline const SessionProtocol* getProtocol() const	{ return this->protocol; }

		inline int getRestrictions() const					{ MutexLockerRead(&this->loggingLock); return this->restrictions; }
		bool getRestriction( SESSION_RESTRICTIONS flag ) const;
		inline int getMaxLoginRetries() const				{ MutexLockerRead(&this->loggingLock); return this->maxLoginRetries; }
		inline const std::string& getWelcomeMessage() const	{ MutexLockerRead(&this->loggingLock); return this->welcomeMsg; }
		inline bool isWelcomePrompted() const				{ MutexLockerRead(&this->loggingLock); return this->welcomeShow; }

		inline const URI& getCurrentLocation() const 		{ MutexLockerRead(&this->currentLock); return this->currentLocation; }
		inline const std::string& getCurrentBus() const		{ MutexLockerRead(&this->currentLock); return this->currentBus; }
		inline long getLastInputTS() const					{ MutexLockerRead(&this->currentLock); return this->lastInputTS; }
		inline const std::string& getPrompt() const			{ MutexLockerRead(&this->currentLock); return this->prompt; }

		const ListT<std::string>& getHistory() const		{ return this->history; }
		unsigned int getHistoryMaxSize() const				{ return this->historyMaxSize; }

		inline const char* getStateAsString() const			{ MutexLockerRead(&this->stateLock); return getStateAsString(this->state); }
		static const char* getStateAsString( Session::SESSION_STATE state );
		static Session::SESSION_STATE getStateFromString( const char* state );

		static DataFieldCollector<Session>* getDataFields();

	protected:
		inline SecurityTokenProvider* getCredentials()		{ return this->credentials; }

//@}
/** name Setters
 * @{
 ******************************************************************************/
	public:
		virtual void setCreatorURI( const URI& uri )		{ this->creator = uri; }
		virtual void setRestriction( SESSION_RESTRICTIONS flag, bool enabled );
		virtual void setRestrictions( int flags );
		virtual void setMaxLoginRetries( int value );
		virtual void setWelcomeMessage( const std::string& value );
		virtual void setWelcomePrompted( bool show );

		virtual void setCurrentLocation( const URI& uri );
		virtual void changeToUserHome();
		virtual void setCurrentBus( const std::string& value );

		void setHistoryMaxSize( unsigned int value )		{ this->historyMaxSize = value; }

	protected:
		virtual WRESULT setState( SESSION_STATE value );

		virtual void setUsernameLogged( const std::string& user )	{ this->usernameLogged = user; }
		virtual void setUsername( const std::string& user )			{ this->username = user; }
		virtual void setCredentials( SecurityTokenProvider* ptr )	{ this->credentials = ptr; }

//@}
	protected:
		void setLastInputNow() const;
		virtual inline const std::string& updatePrompt()	{ MutexLockerWrite(&this->currentLock); return updatePrompt_(); }
		virtual const std::string& updatePrompt_();

	protected:
		virtual void registered() { }
		virtual void unregistered() { }

	protected:
		virtual WRESULT login();

		virtual WRESULT parseInput( const std::string& user_input );
		/**
		 * @brief  Send (output) message to user
		 * @param output_text [in] the message to be sent
		 */

		virtual WRESULT printMessage( const std::string& output_text ) = 0;
		//virtual WRESULT printMessage( const char* output_text ) = 0;

		virtual SecurityToken* signMessage( Message* message, const SecurityToken* source_token = NULL ) const;
		virtual WRESULT postMessage( Message* message );

	private:
		long id;							///< session id (never changes once set)
		URI creator;						///< uri of my creator (never changes once set)
		long creation_ts;					///< timestamp of creation (never changes once set)
		SESSION_STATE state;				///< session state
		MutexRW stateLock;					///< mutex of state

	protected:
		LogContext Log;						///< my log
		BusConnector BusCore;				///< connector to Core
		SessionProtocol* protocol;			///< the i/o processor (convert user's input and responses)

	protected:
		std::string usernameLogged;			///< original logged user (never changes once set)
		std::string username;				///< current user
		SecurityTokenProvider* credentials;	///< session's credentials
		int restrictions;					///< su/sudo restrictions
		int maxLoginRetries;				///< max login retries
		std::string welcomeMsg;				///< welcome message (after login)
		bool welcomeShow;					///< skip welcome message
		MutexRW loggingLock;				///< mutex of { username, credentials, welcome* }

	protected:
		mutable URI currentLocation;		///< target URI, it is like a system path (exec 'pwd' to prompt)
		mutable std::string currentBus;		///< target Bus, see Message::destinationBus, default should be wosh.Bus.Core
		mutable long lastInputTS;			///< timestamp of last user input
		std::string prompt;					///< current prompt
		MutexRW currentLock;				///< mutex of { prompt, currentLocation, currentBus, lastInputTS }

	protected:
		mutable ListT<std::string> history;	///< last executed commands/messages
		unsigned int historyMaxSize;		///< max items of history


	protected:
		friend class wosh::SessionManager;
		friend class wosh::SessionProtocol;



}; // class def







/**
 * @class   wosh::Session_ListChanged
 * @brief   Raised when 
 *
 *
 * @see     wosh::Fact
 * @see     wosh::Session
 ****************************************************************************
 * @version 0.8.462 $Id: Session.h 2883 2010-08-09 14:51:56Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
class Session_ListChanged : public Fact_ListChanged
 {
	WOSH_SERIALIZABLE(wosh::Session_ListChanged)

	public:
		/**
		 * @brief  Empty constructor.
		 */
		Session_ListChanged()
			: Fact_ListChanged( _Session_EVENT_ListChanged ) { }
		/**
		 * @brief  Constructor with initializers.
		 * @param session_id [in] added, updated or removed item 
		 * @param list_event [in] raised event within list/item
		 */
		explicit Session_ListChanged( long session_id, FACT_LIST_EVENT list_event )
			: Fact_ListChanged(session_id, list_event, _Session_EVENT_ListChanged) { }
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		Session_ListChanged( const Session_ListChanged& m )
			: Fact_ListChanged(m) { }
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~Session_ListChanged() { }

	public:
		long getSessionID() const;

}; // class def


}; // namespace wosh

#endif //__WOSH_Core_Session_H__
